package smali

import checkInvalidPackageDir
import copyPathAllFile
import findAllFile
import java.io.File
import java.util.LinkedList

object SmaliCopy {

    /**
     *  需要把"."换成"/" 示例com/combosdk/forBzhan/PluginImpl
     *  通过文件名
     */
    fun copyImportPackage(oldRootPath: String, outRootPath: String, coreFile: File, isMerge: Boolean = false) {
        val currentTimeMillis = System.currentTimeMillis()
        val importPackage = getImportPackage(oldRootPath, coreFile)
        println("需要复制${importPackage.size}个smali文件")
        copySmali(oldRootPath, isMerge, outRootPath, importPackage)
        println("复制完成 用时${System.currentTimeMillis()-currentTimeMillis} ms")
    }
    /**
     *
     *  需要把"."换成"/"  示例 com/combosdk/forBzhan/PluginImpl
     *  通过类名
     */
    fun copyImportPackageForClasses(oldRootPath: String, outRootPath: String,vararg className: String, isMerge: Boolean = false) {
        val currentTimeMillis = System.currentTimeMillis()
        val importPackage = getImportPackageForClassNames(oldRootPath, *className)
        println("需要复制${importPackage.size}个smali文件")
        copySmali(oldRootPath, isMerge, outRootPath, importPackage)
        println("复制完成 用时${System.currentTimeMillis()-currentTimeMillis} ms")
    }
    /**
     *  需要把"."换成"/"
     *  通过包名
     */
    fun copyImportPackageForPackage(oldRootPath: String, outRootPath: String,vararg packageName: String, isMerge: Boolean = false) {
        val currentTimeMillis = System.currentTimeMillis()
        val importPackage = getImportPackageForPackageName(oldRootPath,*packageName)
        println("需要复制${importPackage.size}个smali文件")
        copySmali(oldRootPath, isMerge, outRootPath, importPackage)
        println("复制完成 用时${System.currentTimeMillis()-currentTimeMillis} ms")
    }

    private fun copySmali(
        oldRootPath: String,
        isMerge: Boolean,
        outRootPath: String,
        importPackage: HashMap<String, String>
    ) {
        val classesPath = findClassesPath(oldRootPath)
        val mapOf = HashMap<String, String>()
        classesPath.forEach {
            val name = File(it).name
            if (isMerge) {
                mapOf[it] = "$outRootPath/smali"
            } else {
                mapOf[it] = "$outRootPath/$name"
            }
        }
        importPackage.forEach {
            val fileName = it.key + ".smali"
            val oldPath = it.value + "/$fileName"
            val newPath = mapOf[it.value] + "/$fileName"
            copyPathAllFile(oldPath, newPath, path = "", isCover = true, isLog = false)
        }
    }


    /**
     * 获取引用到的类  根据smali文件   可传入文件或文件夹
     */
    fun getImportPackage(rootPath: String, coreFile: File): HashMap<String, String> {
        val smaliPathMap = HashMap<String, String>()
        val packageNames = HashSet<String>()
        val classesPath = findClassesPath(rootPath)
        classesPath.forEach {
            val invalidPackageDir = LinkedList<String>()
            checkInvalidPackageDir(File(it), invalidPackageDir)
            invalidPackageDir.forEach {
                println("存在无效包名路径(文件夹不能带.)=$it")
            }
        }
        val findAllSmali = findAllSmali(coreFile)
        findAllSmali.forEach { it ->
            val findClass = SmaliClassUtil.findClass(it)
            findClass.forEach {
                packageNames.add(it)
            }
        }
        getNeedCopyFilePathList(classesPath, packageNames, smaliPathMap)
        return smaliPathMap
    }



    /**
     * 获取引用到的类  根据类名    com/xx/aa
     */
    fun getImportPackageForClassNames(rootPath: String,vararg className:  String): HashMap<String, String> {
        val smaliPathMap = HashMap<String, String>()
        val packageNames = HashSet<String>()
        val classesPath = findClassesPath(rootPath)
        classesPath.forEach {
            val invalidPackageDir = LinkedList<String>()
            checkInvalidPackageDir(File(it), invalidPackageDir)
            invalidPackageDir.forEach {
                println("存在无效包名路径(文件夹不能带.)=$it")
            }
        }
        className.forEach {
            packageNames.add(it)
        }
        getNeedCopyFilePathList(classesPath, packageNames, smaliPathMap)
        return smaliPathMap
    }

    /**
     * 获取引用到的类  根据包名  com/xx/aa
     */
    fun getImportPackageForPackageName(rootPath: String,vararg packageNameVar: String): HashMap<String, String> {
        val smaliPathMap = HashMap<String, String>()
        val packageNames = HashSet<String>()
        val classesPath = findClassesPath(rootPath)
        classesPath.forEach {class_path->
            val invalidPackageDir = LinkedList<String>()
            checkInvalidPackageDir(File(class_path), invalidPackageDir)
            invalidPackageDir.forEach {
                println("存在无效包名路径(文件夹不能带.)=$it")
            }
            packageNameVar.forEach { packageName->
                val findAllSmali = findAllSmali(File("$class_path/$packageName"))
                findAllSmali.forEach { smaliPath ->
                    val findClass = SmaliClassUtil.findClass(smaliPath)
                    findClass.forEach {
                        packageNames.add(it)
                    }
                }
            }

        }
        getNeedCopyFilePathList(classesPath, packageNames, smaliPathMap)
        return smaliPathMap
    }


    private fun findAllSmali(nodeFile: File): List<String> {
        val data = LinkedList<String>()
        findAllFile(nodeFile, data) {
            if (it.name.contains(".smali")) {
                return@findAllFile true
            }
            return@findAllFile false
        }
        return data
    }

    private fun findClassesPath(rootPath: String): Set<String> {
        val set = HashSet<String>()
        var smaliFile = File("$rootPath/smali")
        var p = 1
        if (smaliFile.exists()) {
            set.add(smaliFile.absolutePath)
        }
        while (true) {
            p++
            smaliFile = File("$rootPath/smali_classes$p")
            if (smaliFile.exists()) {
                set.add(smaliFile.absolutePath)
            } else {
                break
            }
        }
        return set
    }


    /***
     * @param classesPaths smali  smali_classes1 像这些的绝对路径
     * @param packageNames 包名列表
     * @param smaliPathMap key包名  value 在哪个classesPath下
     */
    private fun getNeedCopyFilePathList(
        classesPaths: Set<String>,
        packageNames: Set<String>,
        smaliPathMap: HashMap<String, String>
    ) {

        val list = LinkedList<String>()

        val set = java.util.HashSet<String>()

        packageNames.forEach {
            checkAddList(list, set, it)
        }

        while (list.size > 0) {
            val pollFirst = list.pollFirst()
            ff@
            for (classRootPath in classesPaths) {
                val smaliPath = "$classRootPath/$pollFirst.smali"
                val file = File(smaliPath)
                if (file.exists()) {
                    smaliPathMap[pollFirst] = classRootPath
                    val findClass = SmaliClassUtil.findClass(smaliPath)
                    findClass.forEach {
                        checkAddList(list, set, it)
                    }
                    break@ff
                }
            }
        }

    }

    private fun checkAddList(list: LinkedList<String>, set: java.util.HashSet<String>, packageName: String) {
        if (!set.contains(packageName)) {
            list.add(packageName)
            set.add(packageName)
        }
    }
}

